﻿using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

namespace VoiceLocal
{
    class Program
    {
        private static string parm =
                "engine_type=local,asr_res_path=fo|res/asr/common.jet,grm_build_path=res/asr/GrmBuilld,sample_rate=16000,result_type=xml,ptt=0,result_encoding = GB2312"
            ;

        static void Main(string[] args)
        {
            // 初始化
            Initialize();
            // 语法参数设置
            Grammar();
            // 开启会话
            var session = StartScymtSession(string.Empty);
            // 写入音频
            WriteAudio(session);
            // 逆初始化
            UnInitialize();
        }

        private static void WriteAudio(string sessionid)
        {
            FileStream fs = new FileStream("test.pcm", FileMode.Open);
            long size = fs.Length;
            while (size > 0)
            {
                var len = (int) (size > 1600 ? 1600 : size);
                var buff = new byte[len];
                fs.Read(buff, 0, len);
                int audioStatus, epStatus = 0, status = 0;
                if (size == fs.Length)
                {
                    audioStatus = 1;
                }
                else
                {
                    audioStatus = size - len <= 0 ? 4 : 2;
                }
                //_voiceEngOperator.WriteAudioBuffer(buff);
                var returnCode = QisrDll.QISRAudioWrite(sessionid, buff, (uint) buff.Length, audioStatus, ref epStatus,
                    ref
                    status);
                if (returnCode != 0)
                {
                    string retMsg = string.Format("QISRAudioWrite异常：返回错误码：{0}", returnCode);
                    throw new Exception(retMsg);
                }
                if (epStatus >= 3 || status == 1)
                {
                    EndScymtSession(sessionid);
                    sessionid = StartScymtSession(sessionid);
                }

                if (status == 0 || status == 5)
                {
                    //Debug.WriteLine("AudioWrite ResultStatus:" + status);
                    //GetAudioResult();
                    int resultStatus = 0;
                    int errorCode = 0;
                    var resultText = QisrDll.QISRGetResult(sessionid, ref resultStatus, 5000, ref errorCode);
                    //                Debug.WriteLine("GetResult ResultStatus:" + resultStatus);
                    if (errorCode != 0)
                    {
                        // LogWriter("QISRGetResult异常：" + errorCode);
                    }
                    var resultStr = Marshal.PtrToStringAnsi(resultText);
                    //LogWriter("识别：" + resultStr);
                    //ProcessVoiceResult(resultStr);
                    if (status != 5) return;
                    EndScymtSession(sessionid);
                    sessionid = StartScymtSession(sessionid);
                }
                size -= len;
                Thread.Sleep(10);
            }
            fs.Close();
            EndScymtSession(sessionid);
        }

        /// <summary>
        /// 结束识别会话
        /// </summary>
        /// <returns></returns>
        private static void EndScymtSession(string sessionId)
        {
            if (string.IsNullOrEmpty(sessionId)) return;
            var ret = QisrDll.QISRSessionEnd(sessionId, "");
            if (ret != 0)
            {
                //  LogWriter(string.Format("QISRSessionEnd 结束识别会话，错误码{0}", ret));
            }
            //lock (_recordBufferQueue)
            //{
            //    if (string.IsNullOrEmpty(sessionId)) return;
            //    SCYReturnCode returnCode = AIPlusMtScylla.SCYMTSessionEnd(sessionId);
            //    if (returnCode != SCYReturnCode.SCY_SUCCESS)
            //    {
            //        LogWriter(string.Format("EndSematicSession 调用接口 [SCYMTSessionEndEx] 返回失败错误码{0}", returnCode));
            //    }
            //    //LogWriter("结束识别会话，返回码：" + returnCode, logLevel: VoiceCloudLogLevel.CallLog);
            //}
        }

        /// <summary>
        /// 开始识别会话
        /// </summary>
        private static string StartScymtSession(string SessionId)
        {
            int ret = 0;
            // QisrDll.QISRSessionEnd(SessionId, "");
            //  string parm = QisrBeginParam.DefaultParam();
            var rst = QisrDll.QISRSessionBegin(null, parm, ref ret);
            if (ret != 0)
            {
                //throw new Exception(string.Format("创建识别会话异常，错误码：{0}", ret));
            }
            if (IntPtr.Zero == rst)
            {
                // throw new Exception("创建识别会话异常，但sessionId为空，返回码：" + ret);
            }
            var sid = Marshal.PtrToStringAnsi(rst);
            //            Debug.WriteLine("SessionStart");
            return sid;
        }

        /// <summary>
        /// 引擎初始化
        /// </summary>
        public static void Initialize()
        {
            //LogWriter("开始语音识别引擎初始化，调用接口：[SCYMTInitialize]", logLevel: VoiceCloudLogLevel.CallLog);
            //初始化识别引擎
            var ret = MspDll.MSPLogin(null, null, "appid = 5b190609");
            if (ret != 0)
            {
                throw new Exception(string.Format("MSPLogin：识别引擎初始化异常，错误码：{0}", ret));
            }


            //LogWriter("语义转写引擎初始化完成，返回结果：" + iesReturnCode, logLevel: VoiceCloudLogLevel.CallLog);
        }

        /// <summary>
        /// 引擎逆初始化
        /// </summary>
        public static void UnInitialize()
        {
            //逆初始化识别引擎
            //LogWriter("开始语音识别引擎逆初始化", logLevel: VoiceCloudLogLevel.CallLog);
            var ret = MspDll.MSPLogout();
            if (ret != 0)
            {
                throw new Exception(string.Format("逆初始化识别引擎异常，错误码：{0}", ret));
            }
            //LogWriter("语义转写引擎逆逆初始化完成，返回结果：" + iesReturnCode, logLevel: VoiceCloudLogLevel.CallLog);
        }

        /// <summary>
        /// 设置语法参数
        /// </summary>
        private static void Grammar()
        {
            string grammarParm = "engine_type = local,asr_res_path=fo|res/asr/common.jet," +
                                 "sample_rate=16000,grm_build_path =res/asr/GrmBuilld";
            var grammarid=new IntPtr();
            var grammarfile = ReadFile("call.bnf");
            GrammarCallBack g = GrammarCallBack;
            int retCode = QisrDll.QISRBuildGrammar("bnf", grammarfile, grammarfile.Length,grammarParm, GrammarCallBack,  grammarid);
        }
        

        public static int GrammarCallBack(int param0, string param1, IntPtr param2)
        {
            object obj = Marshal.PtrToStructure(param2, typeof(UserData));
            return 0;
        }

        /// <summary>  
        /// 读取文件，返回相应字符串  
        /// </summary>  
        /// <param name="fileName">文件路径</param>  
        /// <returns>返回文件内容</returns>  
        private static string ReadFile(string fileName)
        {
            StringBuilder str = new StringBuilder();
            using (FileStream fs = File.OpenRead(fileName))
            {
                long left = fs.Length;
                int maxLength = 100;//每次读取的最大长度  
                int start = 0;//起始位置  
                int num = 0;//已读取长度  
                while (left > 0)
                {
                    byte[] buffer = new byte[maxLength];//缓存读取结果  
                    char[] cbuffer = new char[maxLength];
                    fs.Position = start;//读取开始的位置  
                    num = 0;
                    if (left < maxLength)
                    {
                        num = fs.Read(buffer, 0, Convert.ToInt32(left));
                    }
                    else
                    {
                        num = fs.Read(buffer, 0, maxLength);
                    }
                    if (num == 0)
                    {
                        break;
                    }
                    start += num;
                    left -= num;
                    str = str.Append(Encoding.Default.GetString(buffer));
                }
                str = str.Append("\0");
            }
            return str.ToString();
        }
    }
    
    public struct UserData
    {

        /// int
        public int build_fini;

        /// int
        public int update_fini;

        /// int
        public int errcode;

        /// char[]
        public string grammar_id;
    }
}
